package com.carbon.core.net;

import com.carbon.core.lang.Assert;
import org.apache.commons.lang3.StringUtils;

import javax.servlet.http.HttpServletRequest;

/**
 * @author czq
 * @date 2021-02-24
 */
public class IpUtils {

    /**
     * 内网
     */
    private static final String[] INTRANET_IP = new String[]{"0:0:0:0:0:0:0:1", "127.0.0.1", "192.168"};

    private static final String X_FORWARDED_FOR = "x-forwarded-for";

    private static final String UNKNOWN = "unknown";

    private static final String PROXY_CLIENT_IP = "Proxy-Client-IP";

    private static final String WL_PROXY_CLIENT_IP = "WL-Proxy-Client-IP";

    private static final String HTTP_CLIENT_IP = "HTTP_CLIENT_IP";

    private static final String HTTP_X_FORWARDED_FOR = "HTTP_X_FORWARDED_FOR";

    /**
     * 获取IP地址
     * <p>
     * 使用 nginx 等反向代理软件， 则不能通过 request.getRemoteAddr() 获取IP地址
     * 如果使用了多级反向代理的话，X-Forwarded-For的值并不止一个，
     * 而是一串IP地址，X-Forwarded-For中第一个非 unknown 的有效IP字符串，则为真实IP地址
     */
    public static String getIpAddr(HttpServletRequest request) {
        Assert.isNotNull(request);
        String ip = request.getHeader(X_FORWARDED_FOR);
        if (StringUtils.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader(PROXY_CLIENT_IP);
        }
        if (StringUtils.isEmpty(ip) || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader(WL_PROXY_CLIENT_IP);
        }
        if (StringUtils.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader(HTTP_CLIENT_IP);
        }
        if (StringUtils.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader(HTTP_X_FORWARDED_FOR);
        }
        if (StringUtils.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

    /**
     * 判断是否内部 ip
     *
     * @param ip ip 地址
     * @return 是否内部
     */
    public static boolean isIntranet(String ip) {
        Assert.isNotNull(ip);
        for (String item : INTRANET_IP) {
            if (ip.contains(item)) {
                return Boolean.TRUE;
            }
        }
        return Boolean.FALSE;
    }

}
